#include "qlmodem/task_modem.h"
#include "comm/ota.h"
#include "flash/flash_main.h"
#include "flash/flash_if.h"
#include "misc/misc_api.h"
#include "service/include/swei_ota.h"
#include "service/include/swei_cmd.h"
#include "service/include/swei_downlink.h"
#include "mmgr/include/mmgr_pdp.h"
#include "service/include/swei_l3_pattern.h"
#include "service/include/port/swei_wrapper.h"

/* 4KB */
#define SECTOR_SIZE     (4 * 1024) 

static int32_t sect_offset_l3_lib = 0;
static uint32_t offset_l3_lib = 0;

static uint8_t fw_l3_lib_buff[SECTOR_SIZE] = {0};


static int tbox_l3_lib_erase(void);
static ssize_t tbox_l3_lib_write(const void *buf, size_t len);

static struct file_download l3_lib_download_info = {
    .erase = tbox_l3_lib_erase,
    .write = tbox_l3_lib_write,
    .writable_size = 0,
    .file_type = NO_ENC_FILE,
    .connect_timeout = 5,
    .download_timeout = 10,
    .ver_verify = NULL,
    .auth_gen = NULL,
    .user_agent = NULL,
};

static  l3_lib_download_ctx download_l3_lib_ctx = {
    .is_processing = false,
    .received_len  = 0,  
    .total_len     = 0, 
    .url_len       = 0,
};

l3_lib_pool  l3_pattern_pool = {
    .pool = NULL,
    .size = 0,
    .offset = 0
};

#define  L3_LIB_POOL_SIZE    2*1024 
unsigned char l3_lib_buf[2*1024];

/* 模式库头部结点头指针(主要用来保存模式头部的全局信息) */
static l3_pattern_header_st *l3_pattern_header           = NULL;

/* 模式库-模式节点指针 */
static l3_pattern_content_st *l3_pattern_content_header  = NULL;


int tbox_l3_init_lib_pool(void)
{ 
    if (l3_pattern_pool.pool != NULL)
    {
        swei_free(l3_pattern_pool.pool);
        l3_pattern_pool.offset = 0;
        l3_pattern_pool.size   = 0;
        l3_pattern_pool.pool = NULL;
    }

    l3_pattern_pool.pool = (uint8_t*)swei_malloc(L3_LIB_POOL_SIZE);
    if (l3_pattern_pool.pool == NULL)
    {
        log_e("smartX dynamic rule pool malloc fail");
        return  -SMARTX_PATTERN_MALLOC_DYNAMIC_RULE_POOL_FAIL;
    }
    else
    {
        l3_pattern_pool.offset = 0;
        l3_pattern_pool.size   = L3_LIB_POOL_SIZE;        
        memset(l3_pattern_pool.pool, 0, l3_pattern_pool.size);
    }
}


int tbox_l3_lib_pool_deinit(void)
{
    if (l3_pattern_pool.pool != NULL)
    {
        swei_free(l3_pattern_pool.pool);
        l3_pattern_pool.pool = NULL;
        l3_pattern_pool.offset = 0;
        l3_pattern_pool.size = 0;
        log_d("smartX dynamic rule pool freed successfully");
    }
    else
    {
        log_w("smartX dynamic rule pool is already NULL");
    }

    return SMARTX_SUCCESS;
}


void *tbox_l3_lib_pool_malloc(uint32_t size)
{
   void *ptr = NULL;

   if (l3_pattern_pool.pool == NULL)
   {
       log_e("smartX dynamic pool null");
       return NULL;
   }
   
   if ((l3_pattern_pool.offset + size) > l3_pattern_pool.size)
   {
      log_e("smartX malloc dynamic rule faile, size:%d, offset:%d, pool_size:%d",\
                 size, l3_pattern_pool.offset, l3_pattern_pool.size);
      return NULL;
   }

   ptr = l3_pattern_pool.pool + l3_pattern_pool.offset;
   l3_pattern_pool.offset += size;
   return ptr;
}

void tbox_l3_lib_pool_free(uint32_t size)
{      
	if (l3_pattern_pool.offset >= size){
		l3_pattern_pool.offset -= size;
	}

	if (l3_pattern_pool.offset == 0){
	    memset(l3_pattern_pool.pool, 0, l3_pattern_pool.size);
	}
}

void tbox_l3_reset_lib_pool(void)
{
    //仅清空已经使用的内存
    memset(l3_pattern_pool.pool, 0, l3_pattern_pool.offset);
    l3_pattern_pool.offset = 0;
}

static int tbox_l3_lib_erase(void)
{
    return aad_flash_zone_clear(FILE_L3_LIB_ID, AADL_WAIT | AADL_KEEP_OUTSIDE , 0);
}

int32_t tbox_l3_lib_flash_write(uint64_t received, uint32_t len, unsigned char *buf) 
{
    int32_t ret = 0; 
    
    sect_offset_l3_lib = received / SECTOR_SIZE; 
    
    /* 缓存数据，当数据量达到扇区大小，再写入flash */
    if(offset_l3_lib + len < SECTOR_SIZE) {
        memcpy(&fw_l3_lib_buff[offset_l3_lib], buf, len);
        offset_l3_lib += len;
    } else { 
        while(offset_l3_lib + len >= SECTOR_SIZE) {
            /* buff剩余空间填充数据 */
            memcpy(&fw_l3_lib_buff[offset_l3_lib], buf, SECTOR_SIZE- offset_l3_lib);
            len -= SECTOR_SIZE - offset_l3_lib;
            buf += SECTOR_SIZE - offset_l3_lib;
            offset_l3_lib = 0;
            
            /* 写入flash，并读出来及时校验*/ 
            ret = aad_flash_direct_write(FILE_L3_LIB_ID,\
							            sect_offset_l3_lib * SECTOR_SIZE,\
							            fw_l3_lib_buff,\
							            SECTOR_SIZE, AADL_WAIT | AADL_KEEP_OUTSIDE,\
							            0); 
            if (ret != 0)
            {
                log_e("Fail to save l3 lib into flash! id:%d,%d\r\n", FILE_L3_LIB_ID, ret);
            }    
            
            sect_offset_l3_lib += 1;
      
        }
        
        /* 将剩余未读取数据放入fw_buff中 */
        memcpy(&fw_l3_lib_buff[offset_l3_lib], buf, len);      
        offset_l3_lib += len;        
    }

    return ret;
}


int8_t tbox_l3_lib_flash_flush()
{
    int8_t ret = 0;
    ret = aad_flash_direct_write(FILE_L3_LIB_ID,\
								    sect_offset_l3_lib * SECTOR_SIZE,\
								    fw_l3_lib_buff,\
								    offset_l3_lib,\
								    AADL_WAIT | AADL_KEEP_OUTSIDE,\
								    0);
    
    if (ret != 0)
    {
        log_e("Flush remaining l3 lib fw data failed! id:%d,%d\r\n", FILE_L3_LIB_ID, ret);
        ret = -ENOENT;
    }
    
    return ret;
}

static ssize_t tbox_l3_lib_write(const void *buf, size_t len)
{
   int ret = 0;

    if (buf == NULL){
        return -EINVAL;
    }        
    
    /* 在这里禁止调度来避免flash写入错误 */
    taskENTER_CRITICAL();
    ret = tbox_l3_lib_flash_write(download_l3_lib_ctx.received_len, len, (unsigned char*)buf);
    taskEXIT_CRITICAL();

    if (ret != 0)
    {
        log_e("Fail to save l3 lib into flash! id:%d,ret:%d\r\n", FILE_L3_LIB_ID, ret);
        return ret;
    } 
    
    download_l3_lib_ctx.received_len += len;
    
    if (download_l3_lib_ctx.total_len == 0){        
		qltask_modem_file_download_progress_get(&download_l3_lib_ctx.total_len, NULL);
    }
        
    if (download_l3_lib_ctx.total_len > 0
        && download_l3_lib_ctx.received_len >= download_l3_lib_ctx.total_len) {
        log_d("download l3 lib success-total_len:%d recv_len",download_l3_lib_ctx.total_len,download_l3_lib_ctx.received_len);
        swei_netProtocol_ack_downlink_cmd(DOWN_LINK_CMD_DOWNLOAD_STATIC_PATTERN, CMD_SUCCESS, true);
        
        /* 将剩余的固件缓存直接写入flash */
        taskENTER_CRITICAL();
        tbox_l3_lib_flash_flush();
        taskEXIT_CRITICAL();    

        download_l3_lib_ctx.is_processing = false;
        download_l3_lib_ctx.received_len  = 0;
        download_l3_lib_ctx.total_len     = 0;
        memset(download_l3_lib_ctx.md5, 0, sizeof(download_l3_lib_ctx.md5));
        memset(download_l3_lib_ctx.url, 0, sizeof(download_l3_lib_ctx.url));
        swei_l3_lib_load_from_flash();
    }
        
    return len;
}

/* 用于计算http服务中url路径中的host参数长度,用于解析url和host 
 * https://ebike-api-test.sailvan.net/api/v1/iot-storage/azure/log?key=496c94b62b8d465fa83c8f954fd225d4 */
unsigned short get_host_para_len(const         unsigned char *p_data)
{
    const char *start = strstr((const char *)p_data, "://");
    if (start) 
    {
        start += 3;
        const char *end = strchr(start, '/');
        
        if (!end)
        {
            return 0;
        }
        else
        {
			unsigned short host_len = (const unsigned char *)end - p_data;
			return  host_len;
        }        
    } 
    else 
    {
        return 0;
    }
}

static int tbox_parse_pattern_download_info(int cmd_len,  const uint8_t *data, l3_lib_download_ctx *ctx)
{
    int             loop = 0;
    uint16_t        total_len = 0, host_len = 0; 
    const uint8_t   *p_data_tmp = NULL;
    uint16_t        url_len;
   
    memset(ctx->md5, 0, sizeof(ctx->md5));
    memset(ctx->url, 0, sizeof(ctx->url));
    
    for (; loop < MD5_VAL_HEX_LEN; loop++)
    {
        sprintf((char *)ctx->md5 + strlen((char *)ctx->md5), "%02x", data[loop]);
    }

    ctx->md5[MD5_STR_LEN] = '\0';
    
    /* LV结构-取得L总长度 */
    p_data_tmp = data + MD5_VAL_HEX_LEN;
    total_len  = (p_data_tmp[0] << 8 | p_data_tmp[1]);
    
    if (total_len > L3_PATTERN_URL_LEN)
    {
        log_e("download l3 pattern url content len error,total_len:%d", total_len);
        return  PARSE_DOWNLOAD_PATTERN_INFO_ERROR;
    }
    
    /* 偏移过L字段两个字节 */
    p_data_tmp = p_data_tmp + 2;
    host_len = get_host_para_len(p_data_tmp);
    if (host_len <= 0)
    {
		log_e("download l3 pattern host len error,host_len:%d", host_len);
		return  PARSE_DOWNLOAD_PATTERN_INFO_ERROR;
    }
    
    url_len = (total_len);
    ctx->url_len = url_len;
    memmove_s(ctx->url, L3_PATTERN_URL_LEN, p_data_tmp, url_len);
    
    log_i("download pattern info success , url:%s, md5:%s, cmd_len:%d, host_len:%d, url_len:%d", ctx->url, ctx->md5,total_len,host_len,url_len);
    
    return PARSE_DOWNLOAD_PATTERN_INFO_SUCCESS;
}

static DLCMD_RET_TYPE_ENUM tbox_l3_lib_download_handler(
	DOWN_LINK_CMD_ENUM cmd_id, 
	uint16_t cmd_opcode, 
	const unsigned char * p_data, 
	uint32_t data_len
)
{
	int res = 0;
	int retry = 2;
    
    if (NULL == p_data){
        return DLCMD_RET_ERROR;
    }

    if (download_l3_lib_ctx.is_processing == true){
        swei_netProtocol_ack_downlink_cmd(cmd_id, CMD_IN_PATTERN_DOWNLOAD, true);
		return DLCMD_RET_ERROR;
    }

    if ((mmgr_pdp_status_get() == true) && (is_tbox_ota() == false)) {
    
		download_l3_lib_ctx.received_len  = 0;
		download_l3_lib_ctx.total_len     = 0;

        /* 为避免失败，尝试两次 */
        for (int i = 0; i < retry; i++) {   
            tbox_parse_pattern_download_info(data_len, p_data, &download_l3_lib_ctx);
            //越界保护
            if (download_l3_lib_ctx.url_len > 190){
                log_e("l3 lib url len error, url_len:%d", download_l3_lib_ctx.url_len);
                return DLCMD_RET_ERROR; 
            }
            memcpy(l3_lib_download_info.url, download_l3_lib_ctx.url, download_l3_lib_ctx.url_len);
            res = qltask_modem_file_download_start(&l3_lib_download_info);
           
            if (0 == res) {
                download_l3_lib_ctx.is_processing = true;
                break;                
            }
        }
        
        if (0 != res) {
            log_e("Fail to start l3 lib download, res: %d", res);
            return DLCMD_RET_ERROR;
        }
    }
    return  DLCMD_RET_CONTINUE;
}

uint16_t swap_endian_short(uint16_t value) 
{
    return (value >> 8) | (value << 8);
}

uint32_t swap_endian_int(uint32_t value) 
{
    return ((value >> 24) & 0xFF) |
           ((value >> 8) & 0xFF00) |
           ((value << 8) & 0xFF0000) |
           ((value << 24) & 0xFF000000);
}

static l3_action_st* tbox_parse_l3_actions(const uint8_t *p_pattern_buf, char static_flag)
{
    uint16_t  offset = 0;
    uint16_t  action_len = 0;
    uint8_t   action_id = 0, action_type = 0, action_value_type = 0, action_cnt = 0;
    uint32_t  action_value_tmp = 0, loop = 0;
    l3_action_st *p_l3_action = NULL;
    
    if (static_flag == true){
        p_l3_action = (l3_action_st *)tbox_l3_lib_pool_malloc(sizeof(l3_action_st));
    }  

    if (p_l3_action == NULL)
	{
        log_e("alloc l3 action fail");
        return NULL;
    }

    p_l3_action->p_l3_action_next = NULL;
    action_len = *(uint16_t *)(p_pattern_buf+offset);
    action_len = swap_endian_short(action_len);
    offset += 2;

    action_id = *(uint8_t *)(p_pattern_buf+offset);
    offset += 1;

    action_type = *(uint8_t *)(p_pattern_buf+offset);
    offset += 1;

    action_value_type = *(uint8_t *)(p_pattern_buf+offset);
    offset += 1;

    action_cnt = *(uint8_t *)(p_pattern_buf+offset);
    offset += 1;

    p_l3_action->action_len         = action_len;
    p_l3_action->action_id          = action_id;
    p_l3_action->action_type        = action_type;
    p_l3_action->action_para_type   = action_value_type;
    p_l3_action->action_para_num    = action_cnt;
    memset(p_l3_action->action_para_value, 0x00, sizeof(p_l3_action->action_para_value));

    /* 越界保护异常检查, 解析本次动作失败 */
	if (action_cnt >= MAX_EXEC_ACTION_NUM)
	{
	    log_e("action values exceeds maximum action_cnt:%d",action_cnt);
	    if (static_flag == true){
	         swei_free(p_l3_action);
	    }	   
	    return NULL;
	}
	
    switch (action_value_type) 
    {     
		/* 四字节类型 */
		case INT32_VAL:
		case UINT32_VAL:
		    for (; loop < action_cnt; loop++)
		    {
		        action_value_tmp = *(uint32_t *)(p_pattern_buf+offset);
		        p_l3_action->action_para_value[loop] = swap_endian_int(action_value_tmp);;
		        offset += sizeof(uint32_t);		        
		    }
			break;

		/* string类型和object类型后续再增加 */
		case STRING_VAL:
		case OBJECT_VAL:
		case RESERVED_VAL:
			break;

		default:
			log_e("unknown action value type:%d",action_value_type);	
			if (static_flag == true){
			    swei_free(p_l3_action);
			}			
			return NULL;
    }
    
    return p_l3_action;
}

static l3_indicators_st* tbox_parse_l3_indicators(const uint8_t *p_pattern_buf,char static_flag)
{
    uint16_t  offset = 0, loop = 0;
    uint16_t  indicators_len = 0;
    uint8_t   indicators_id = 0, indicators_type = 0, indicators_match = 0, value_type = 0,value_cnt = 0;
    uint32_t  indicators_val = 0;     
    l3_indicators_st *p_l3_indicators = NULL;
    
    if (static_flag == true){
        p_l3_indicators = (l3_indicators_st *)tbox_l3_lib_pool_malloc(sizeof(l3_indicators_st));
    }

    if (p_l3_indicators == NULL)
	{
        log_e("alloc l3 indicators fail");
        return NULL;
    }
	
    p_l3_indicators->p_l3_indicators_next = NULL;

   
    indicators_len = *(uint16_t *)(p_pattern_buf+offset);
    indicators_len = swap_endian_short(indicators_len);
    offset += 2;
 
    indicators_id = *(uint8_t *)(p_pattern_buf+offset);
    offset += 1;
 
    indicators_type = *(uint8_t *)(p_pattern_buf+offset);
    offset += 1;
   
    indicators_match = *(uint8_t *)(p_pattern_buf+offset);
    offset += 1;
   
    value_type = *(uint8_t *)(p_pattern_buf+offset);
    offset += 1;
   
    value_cnt = *(uint8_t *)(p_pattern_buf+offset);
    offset += 1;
  
    p_l3_indicators->indicator_len   = indicators_len;
    p_l3_indicators->indicator_id    = indicators_id;
    p_l3_indicators->indicator_type  = indicators_type;
    p_l3_indicators->match_type      = indicators_match;
    p_l3_indicators->vale_type       = value_type;
    p_l3_indicators->value_num       = value_cnt;
    memset(p_l3_indicators->value, 0x00, sizeof(p_l3_indicators->value));

	if (value_cnt >= MAX_L3_INDICATION_CNT)
	{
	    log_e("number of indicators exceeding the maximum value_cnt:%d",value_cnt );
	    if (static_flag == true){
	        swei_free(p_l3_indicators);
	    }	   
	    return NULL;
	}
	
    /* 根据值类型和值个数解析值,该指标ID有多个值的话,值类型都是一样 */
    switch (value_type) 
    {
		case INT32_VAL:
		case UINT32_VAL:
		    for (; loop < value_cnt; loop++)
		    {
		        indicators_val = *(uint32_t *)(p_pattern_buf+offset);
                p_l3_indicators->value[loop] = swap_endian_int(indicators_val);
		        offset += sizeof(uint32_t);
		    }
		    break;

		/* string类型和object类型后续再增加 */
		case STRING_VAL:
		case OBJECT_VAL:
	    case RESERVED_VAL:
		    break;

		default:
		    log_e("unknown indicator value type:%d",value_type);
		    if (static_flag == true){		        
		        swei_free(p_l3_indicators);
		    }
		    return NULL;
    }
	
    return p_l3_indicators;
}

static  void tbox_l3_insert_pattern_node(l3_pattern_content_st *p_l3_pattern)
{
    l3_pattern_content_st *p_temp_l3_pattern = l3_pattern_content_header;
	
    while(p_temp_l3_pattern->p_l3_pattern_next != NULL)
	{
        p_temp_l3_pattern = p_temp_l3_pattern->p_l3_pattern_next;
    }
	
    p_l3_pattern->p_l3_pattern_next = NULL;
    p_temp_l3_pattern->p_l3_pattern_next = p_l3_pattern;
}

static void tbox_l3_insert_pattern_value_node(l3_pattern_content_st *p_l3_pattern, l3_indicators_st *p_l3_indicators)
{
    /* 检查是不是该模式下的第一个指标结点*/
    if (p_l3_pattern->p_l3_indicators == NULL)
	{
        p_l3_pattern->p_l3_indicators = p_l3_indicators;
        p_l3_indicators->p_l3_indicators_next = NULL;
    }
	else
	{
        l3_indicators_st *p_temp_l3_indicators = p_l3_pattern->p_l3_indicators;
        while (p_temp_l3_indicators->p_l3_indicators_next != NULL)
		{
            p_temp_l3_indicators = p_temp_l3_indicators->p_l3_indicators_next;
        }
        p_l3_indicators->p_l3_indicators_next = NULL;
        p_temp_l3_indicators->p_l3_indicators_next = p_l3_indicators;
    }
}

static void tbox_l3_insert_action_value_node(l3_pattern_content_st *p_l3_pattern, l3_action_st *p_l3_action)
{
    /* 检查是不是该模式下的第一个指标结点*/
    if (p_l3_pattern->p_l3_action == NULL){
        p_l3_pattern->p_l3_action = p_l3_action;
        p_l3_pattern->p_l3_pattern_next = NULL;
    }else{
        l3_action_st *p_temp_l3_action = p_l3_pattern->p_l3_action;
        while (p_temp_l3_action->p_l3_action_next != NULL)
		{
            p_temp_l3_action = p_temp_l3_action->p_l3_action_next;
        }
        p_l3_action->p_l3_action_next = NULL;
        p_temp_l3_action->p_l3_action_next = p_l3_action;
    }
}

static int tbox_parse_l3_pattern_info(const uint8_t *p_pattern_buf)
{
    uint16_t  pattern_len = 0,  pattern_loop = 0;
    uint16_t  pattern_total_nmu = l3_pattern_header->pattern_cnt;
    uint32_t  pattern_id = 0, offset = 0;
    uint8_t   priority = 0, indicators_cnt = 0, action_cnt = 0;

    for (; pattern_loop < pattern_total_nmu; pattern_loop++)
	{
        /* 模式内容长度 */
        pattern_len = *(uint16_t *)(p_pattern_buf+offset);
        pattern_len = swap_endian_short(pattern_len);
        offset += 2;
		
        if (!((pattern_len > 0) && (pattern_len < 0xFFFF)))
		{
            log_e("error pattern_len:%d",pattern_len);
            return -SMARTX_PARSE_PATTERN_INFO_FAIL;
        }
		
        /* 做下长度有效性检查,头部长度+模式长度已经大于了总长度  */
        if ((l3_pattern_header->head_len + pattern_len) > l3_pattern_header->content_len)
		{
            log_e("l3 lib len check error,head_len:%d, pattern_len%d, content_len:%d",\
                   l3_pattern_header->head_len,\
                   pattern_len,\
                   l3_pattern_header->content_len);
            return -SMARTX_LIB_CHECK_LEN_ERROR;
        }		
      
        l3_pattern_content_st *p_l3_pattern = (l3_pattern_content_st *)tbox_l3_lib_pool_malloc(sizeof(l3_pattern_content_st));

        if (p_l3_pattern == NULL)
		{
            log_e("alloc p_l3_pattern fail");
            return -SMARTX_MEM_ALLOC_FAIL;
        }

        p_l3_pattern->p_l3_pattern_next = NULL;
        
        pattern_id = *(uint32_t *)(p_pattern_buf+offset);
        pattern_id = swap_endian_int(pattern_id);
        offset += 4;
     
        priority = *(uint8_t *)(p_pattern_buf+offset);
        offset += 1;		
      
        indicators_cnt = *(uint8_t *)(p_pattern_buf+offset);
        offset += 1;
      
        action_cnt = *(uint8_t *)(p_pattern_buf+offset);
        offset += 1;
		
        p_l3_pattern->pattern_id          = pattern_id;
        p_l3_pattern->priority            = priority;
        p_l3_pattern->indicators_cnt      = indicators_cnt;
        p_l3_pattern->action_cnt          = action_cnt;
        p_l3_pattern->pattern_content_len = pattern_len;
        p_l3_pattern->p_l3_pattern_next   = NULL; 
        p_l3_pattern->p_l3_indicators     = NULL; 
        p_l3_pattern->p_l3_action         = NULL;
        
        uint16_t indicators_loop = 0;
        for (; indicators_loop < p_l3_pattern->indicators_cnt; indicators_loop++)
		{           
            l3_indicators_st* p_indicators = tbox_parse_l3_indicators(p_pattern_buf+offset, true);
            if (p_indicators == NULL)
			{
			    log_e("failed to parse current indicator");
            }
			else
			{
				/* 这里还要跳过indicator_len字段本身2个字节 */
	            offset = offset + p_indicators->indicator_len+2;				
	      
	            tbox_l3_insert_pattern_value_node(p_l3_pattern, p_indicators);
			}            
        }
	
        uint16_t action_loop = 0;
        for (; action_loop < p_l3_pattern->action_cnt; action_loop++)
		{
            l3_action_st* p_action = tbox_parse_l3_actions(p_pattern_buf+offset, true);
            if (p_action == NULL)
			{
			    log_e("failure to parse an actionl");
            }
            else
            { 
	            offset = offset + p_action->action_len+2;
	            tbox_l3_insert_action_value_node(p_l3_pattern, p_action);
            }
        }
        
        tbox_l3_insert_pattern_node(p_l3_pattern);
    }
	
    return SMARTX_SUCCESS;
}

void tbox_printf_l3_pattern_info(void)
{
    if (l3_pattern_header == NULL)
	{
        log_e("l3_pattern_header null");
        return;
    }

    log_i("*********pattern header info***************");
    log_i("start_flag:0x%x",   l3_pattern_header->start_flag);
    log_i("content_len:%d",    l3_pattern_header->content_len);
    log_i("head_len:%d",       l3_pattern_header->head_len);
    log_i("pattern_type:%d",   l3_pattern_header->pattern_type);
    log_i("car_type:%s",       l3_pattern_header->p_car_type);
    log_i("version_id:0x%x",   l3_pattern_header->pattern_version_id);
    log_i("version_info:%s",   l3_pattern_header->p_pattern_version);
    log_i("published_time:%u", l3_pattern_header->published_time);
    log_i("pattern_cnt:%d",    l3_pattern_header->pattern_cnt);
    
    if (l3_pattern_content_header == NULL)
	{
        log_e("l3_pattern_content_header null");
        return;
    }

    int cnt = 0;
    l3_pattern_content_st *l3PatternContentTemp = l3_pattern_content_header->p_l3_pattern_next;
    while (l3PatternContentTemp != NULL){
        log_i("**********the[%d]st pattern info begin*************",cnt);
        log_i("pattern_content_len:%d",     l3PatternContentTemp->pattern_content_len);
        log_i("pattern_id:0x%x",            l3PatternContentTemp->pattern_id);
        log_i("priority:%d",                l3PatternContentTemp->priority);
        log_i("indicators_cnt:%d",          l3PatternContentTemp->indicators_cnt);
        log_i("action_cnt:%d",              l3PatternContentTemp->action_cnt);
        l3_indicators_st *p_l3_indicators = l3PatternContentTemp->p_l3_indicators;
        log_i("~~~~~~~~~~~~indicator info~~~~~~~~~~~~~~~");
        while(p_l3_indicators != NULL){
            log_i("indicator_len:%d",     p_l3_indicators->indicator_len);
            log_i("indicator_id:0x%x",    p_l3_indicators->indicator_id);
            log_i("indicator_type:%d",    p_l3_indicators->indicator_type);
            log_i("match_type:%d",        p_l3_indicators->match_type);
            log_i("vale_type:%d",         p_l3_indicators->vale_type);
            log_i("value_num:%d",         p_l3_indicators->value_num);

            if (p_l3_indicators->value_num == 1)
            {
                log_i("indicator_value:%d",(int32_t)p_l3_indicators->value[0]);
            }

            if (p_l3_indicators->value_num == 2)
            {
                log_i("indicator_value:%d %d",(int32_t)p_l3_indicators->value[0],(int32_t)p_l3_indicators->value[1]);
            }

            if (p_l3_indicators->value_num == 3)
            {
                log_i("indicator_value:%d %d %d",(int32_t)p_l3_indicators->value[0],(int32_t)p_l3_indicators->value[1],(int32_t)p_l3_indicators->value[2]);
            }

            p_l3_indicators = p_l3_indicators->p_l3_indicators_next;
        }
		
        l3_action_st *p_l3_action = l3PatternContentTemp->p_l3_action;
        log_i("~~~~~~~~~~~~action info~~~~~~~~~~~~~~~~");
        while(p_l3_action != NULL){
            log_i("action_len:%d",          p_l3_action->action_len);
            log_i("action_id:0x%x",         p_l3_action->action_id);
            log_i("action_type:%d",         p_l3_action->action_type);
            log_i("action_para_type:%d",    p_l3_action->action_para_type);
            log_i("action_num:%d",          p_l3_action->action_para_num);


            if (p_l3_action->action_para_num == 2)
            {
                log_i("action_value:%d %d", (int32_t)p_l3_action->action_para_value[0],(int32_t)p_l3_action->action_para_value[1]);
            }

            if (p_l3_action->action_para_num == 1)
            {
                log_i("action_value:%d",(int32_t)p_l3_action->action_para_value[0]);
            }

            if (p_l3_action->action_para_num == 3)
            {
                log_i("action_value:%d %d %d",(int32_t)p_l3_action->action_para_value[0],(int32_t)p_l3_action->action_para_value[1],(int32_t)p_l3_action->action_para_value[2]);
            }

            p_l3_action = p_l3_action->p_l3_action_next;
        }
        cnt++;
        l3PatternContentTemp = l3PatternContentTemp->p_l3_pattern_next;
    }
}

int tbox_parse_l3_lib(void)
{
    int result = SMARTX_SUCCESS;	
  
    uint16_t  car_type_len = 0, offset = 0;
    
    //暂时忽略文件CRC校验
    
    /* 起始标志 */
    l3_pattern_header->start_flag   =  *(uint16_t *)l3_lib_buf;
    offset += 2;

    l3_pattern_header->content_len =  *(uint16_t *)(l3_lib_buf+offset);
    l3_pattern_header->content_len =  swap_endian_short(l3_pattern_header->content_len);
    offset += 2;

    l3_pattern_header->pattern_type  =  *(uint8_t *)(l3_lib_buf+offset);
    offset +=1;

	log_i("content_len:%d",l3_pattern_header->content_len);	
  
    car_type_len = *(uint16_t *)(l3_lib_buf+offset);
    car_type_len = swap_endian_short(car_type_len);
    offset += 2;

	log_i("car_type_len:%d",car_type_len);
	
    if ((car_type_len > 0) && (car_type_len < 0xFFFF))	
	{
       
        /* 申请空间 */
        l3_pattern_header->p_car_type = (uint8_t *)tbox_l3_lib_pool_malloc(car_type_len);

        if (l3_pattern_header->p_car_type == NULL)
		{
            log_e("alloc car type error");
            return -SMARTX_MEM_ALLOC_FAIL;
        }
		else
		{
            memcpy(l3_pattern_header->p_car_type, l3_lib_buf+offset,car_type_len);
            offset += car_type_len;
        }
    }
	else
	{
	    /* 车辆类型可以为空 */
        log_w("no car teyp car_type_len:%d",car_type_len);
        //return -SMARTX_LIB_FILE_PARSE_FAIL;
    }	
 
    l3_pattern_header->pattern_version_id =  *(uint16_t *)(l3_lib_buf+offset);
    l3_pattern_header->pattern_version_id =  swap_endian_short(l3_pattern_header->pattern_version_id);
    offset += 2;
 
    uint16_t  string_version_len = 0;
    string_version_len  = *(uint16_t *)(l3_lib_buf+offset);
    string_version_len = swap_endian_short(string_version_len);
    offset += 2;

	log_i("string_version_len:%d",string_version_len);
    if ((string_version_len > 0) && (string_version_len < 0xFFFF))
	{
        l3_pattern_header->p_pattern_version = (char *)tbox_l3_lib_pool_malloc(string_version_len+1);
        if (l3_pattern_header->p_pattern_version == NULL)
		{
            log_e("alloc string version error");
            return -SMARTX_MEM_ALLOC_FAIL;
        }
		else
		{
            memcpy(l3_pattern_header->p_pattern_version, l3_lib_buf+offset,string_version_len);
            offset += string_version_len;
            l3_pattern_header->p_pattern_version[string_version_len] = '\0';
            log_e("l3 version info:%s",l3_pattern_header->p_pattern_version);
        }
    }
	else
	{
        log_e("error string_version_len:%d",string_version_len);
        return -SMARTX_LIB_FILE_PARSE_FAIL;
    }
  
    l3_pattern_header->published_time = *(uint32_t *)(l3_lib_buf+offset);
    l3_pattern_header->published_time = swap_endian_int(l3_pattern_header->published_time);
    offset += 4;
 
    uint16_t copyright_len = 0;
    copyright_len = *(uint16_t *)(l3_lib_buf + offset);
    copyright_len = swap_endian_short(copyright_len);
    offset += 2;

	log_i("copyright_len:%d",copyright_len);
	
    if ((copyright_len > 0) && (copyright_len < 0xFFFF))
	{
	    /* 只偏移,先不保存版权信息 */
        offset += copyright_len;
    }
	else
	{
        log_e("error copyright_len:%d",copyright_len);
        return -SMARTX_LIB_FILE_PARSE_FAIL;
    }
    
    uint16_t  pattern_cnt = 0;
    pattern_cnt = *(uint16_t *)(l3_lib_buf + offset);
    pattern_cnt = swap_endian_short(pattern_cnt);
    offset += 2;
    if (!((pattern_cnt > 0) && (pattern_cnt < 0xFFFF)))
	{
        log_e("error pattern_cnt:%d",pattern_cnt);
        return -SMARTX_LIB_FILE_PARSE_FAIL;
    }
   
    l3_pattern_header->pattern_cnt = pattern_cnt;
   
    l3_pattern_header->head_len = (offset);
   
    result = tbox_parse_l3_pattern_info(l3_lib_buf+offset);   
    if (result != SMARTX_SUCCESS)
    {
        log_e("l3 parse pattern fail, result:%d",result);
        return result;
    }	
    
    return SMARTX_SUCCESS;
}

void tbox_l3_deinit_lib(void)
{
	l3_pattern_content_header = NULL;
	l3_pattern_header = NULL;
	tbox_l3_reset_lib_pool();
}

void tbox_l3_lib_init()
{
    int ret; 
    
	l3_pattern_header = (l3_pattern_header_st *)tbox_l3_lib_pool_malloc(sizeof(l3_pattern_header_st));

	if (l3_pattern_header == NULL)
	{
		log_e("l3_pattern_header_st malloc fail");
	}
	else
	{	
		l3_pattern_header->content_len		  = 0x00;
		l3_pattern_header->crc				  = 0x00;
		l3_pattern_header->p_car_type		  = NULL;
		l3_pattern_header->p_pattern_version  = NULL;
		l3_pattern_header->pattern_cnt		  = 0x00;
		l3_pattern_header->pattern_type 	  = 0x00;
		l3_pattern_header->pattern_version_id = 0x00;
		l3_pattern_header->published_time	  = 0x00;
		l3_pattern_header->start_flag		  = 0x00;
	}
	
	l3_pattern_content_header = (l3_pattern_content_st *)tbox_l3_lib_pool_malloc(sizeof(l3_pattern_content_st));

	if (l3_pattern_content_header == NULL)
	{
		log_e("l3_pattern_content_header malloc fail");
		tbox_l3_lib_pool_free(sizeof(l3_pattern_header_st));
	}
	else
	{
		l3_pattern_content_header->indicators_cnt	 = 0x00;
		l3_pattern_content_header->action_cnt		 = 0x00;
		l3_pattern_content_header->p_l3_action		 = NULL;
		l3_pattern_content_header->p_l3_indicators	 = NULL;
		l3_pattern_content_header->p_l3_pattern_next = NULL;
	}
}

int swei_l3_lib_load_from_flash(void)
{
    int res = 0,ret = SMARTX_SUCCESS;
    int lib_content_len = 0;
    
    unsigned char buf[4];

    memset(buf, 0, 4);
    
    //先读4个字节,AB AB + 两字节内容长度
    res = aad_flash_direct_read(FILE_L3_LIB_ID, 0, buf, 4);
    if (0 > res){
         log_e("read l3 lib flash error, error reason: %s", errno_str(res)); 
         return -1;
    }

    memset(l3_lib_buf, 0x0, 2*1024);
    //存储区域有效
    if ((buf[0] == 0xAB) && (buf[1] == 0xAB) && buf[2]!= 0xFF && buf[3] != 0xFF){
        memcpy(l3_lib_buf, buf, 4);
        //读取剩下的内容,内容长度+2
        lib_content_len = (buf[2] << 8) | buf[3];
		res = aad_flash_direct_read(FILE_L3_LIB_ID, 4, &l3_lib_buf[4], lib_content_len+2);
		if (0 > res){
			log_e("read l3 lib flash error, error reason: %s", errno_str(res));
			return -1;
		}
    }else{
        log_e("l3 lib flash invalid, buf[0]:%d buf[1]:%d",buf[0],buf[1]);
        return -1;
    }
    
    tbox_l3_deinit_lib();
    tbox_l3_lib_init();    
  
    //从flash读取完毕开始加载
    ret = tbox_parse_l3_lib();
    if (ret != SMARTX_SUCCESS){
        tbox_l3_deinit_lib();
        log_e("parse l3 lib fail,ret:0x%x",ret);
        return -1;
    }

    log_d("load l3 lib success,pool_size:%d,offet:%d",l3_pattern_pool.size, l3_pattern_pool.offset);
    tbox_printf_l3_pattern_info();
    return 0;
}

int swei_l3_lib_module_init(void)
{
	swei_downlink_cmd_register(DOWN_LINK_CMD_DOWNLOAD_STATIC_PATTERN, tbox_l3_lib_download_handler);

	tbox_l3_init_lib_pool();
	tbox_l3_lib_init();
	swei_l3_lib_load_from_flash();
	
	return SMARTX_SUCCESS;
}

